package com.ziytek.web.citizen.job;

import com.ziytek.web.citizen.config.ThreadPrintConfigInit;
import com.ziytek.web.citizen.constant.NumConstant;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

/**
 * @author fenghx
 * @version v1.0
 * @className RunningJob
 * @descripton 程序正在运行中
 * @date 2023/4/11 20:07
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RunningJob {
    private final ThreadPrintConfigInit threadPrintConfigInit;

    @PostConstruct
    public void estimatedOptimalThreadCountInit() {
        log.info("Estimated number of threads in the current operating environment threads: {}", getEstimatedOptimalThreadCount());
    }

    @Scheduled(fixedRateString = "${scheduled.runDelay}")
    public void running() {

        var threadInfo = ManagementFactory.getThreadMXBean();
        var threadConfig = threadPrintConfigInit.getThreadConfig();
        // 打印线程信息
        if (threadConfig != null && threadConfig.isThreadCountPrint()) {
            printThreadInfo(threadInfo);
        }

        // 打印线程名称
        if (threadConfig != null && threadConfig.isThreadNamePrint()) {
            printThreadName(threadInfo);
        }

        // 查找死锁线程
        if (threadConfig != null && threadConfig.isDeadlockedThreadsPrint()) {
            printDeadlockedThreads(threadInfo);
        }

        // 查找等待监视器锁的线程
        if (threadConfig != null && threadConfig.isDeadlockedMonitorsPrint()) {
            printDeadlockedMonitors(threadInfo);
        }

        // 打印所有线程的总CPU时间
        if (threadConfig != null && threadConfig.isAllThreadsTotalCpuTimePrint()) {
            printAllThreadsTotalCpuTime(threadInfo);
        }

        // 程序正在运行中
//        log.info("The program is running.");
    }


    private void printThreadInfo(ThreadMXBean threadInfo) {
        // 获取当前所有活动线程的概要信息
        var threadCount = threadInfo.getThreadCount();
        // 获取峰值线程数
        var peakThreadCount = threadInfo.getPeakThreadCount();
        // 获取总启动线程数
        var totalStartedThreadCount = threadInfo.getTotalStartedThreadCount();
        // 获取当前守护线程的数量
        var daemonThreadCount = threadInfo.getDaemonThreadCount();
        // 获取当前线程的CPU时间
        //long currentThreadCpuTime = threadInfo.getCurrentThreadCpuTime();

        var msg = "";
        msg += String.format("Get peak thread count peak threads:%s,", peakThreadCount);
        msg += String.format("Get the summary information of all current active threads Total threads:%s,", threadCount);
        msg += String.format("Get the current number of daemon threads, Daemon threads:%s,", daemonThreadCount);
        msg += String.format("Get the total number of startup threads total started threads:%s.", totalStartedThreadCount);
        log.info(msg);
    }

    private void printThreadName(ThreadMXBean threadInfo) {
        //获取到一个描述线程信息的数组
        var threadInfos = threadInfo.dumpAllThreads(false, false);
        //打印线程的名称
        for (ThreadInfo info : threadInfos) {
            log.info("线程名称:{}", info.getThreadName());
        }
    }

    private void printDeadlockedThreads(ThreadMXBean threadInfo) {
        // 查找死锁线程 (查找因为等待获得对象监视器或可拥有同步器而处于死锁状态的线程循环)
        var deadlockedThreads = threadInfo.findDeadlockedThreads();
        if (deadlockedThreads == null || deadlockedThreads.length == 0) {
            return;
        }

        var deadlockedThreadInfos = threadInfo.getThreadInfo(deadlockedThreads);
        for (ThreadInfo info : deadlockedThreadInfos) {
            log.info("线程id为{},死锁线程名为{}的线程已经发生死锁，需要的锁正被线程{}持有。", info.getThreadId(), info.getThreadName(), info.getLockOwnerName());
        }
    }

    private void printDeadlockedMonitors(ThreadMXBean threadInfo) {
        // 查找等待监视器锁的线程 (找到处于死锁状态（等待获取对象监视器）的线程的周期。即线程被阻塞)
        var deadlockedMonitors = threadInfo.findMonitorDeadlockedThreads();
        if (deadlockedMonitors == null || deadlockedMonitors.length == 0) {
            return;
        }

        var deadlockedMonitorsThreadInfos = threadInfo.getThreadInfo(deadlockedMonitors);
        for (ThreadInfo info : deadlockedMonitorsThreadInfos) {
            log.info("查找等待监视器锁的线程名称:{}", info.getThreadName());
        }
    }

    private void printAllThreadsTotalCpuTime(ThreadMXBean threadInfo) {
        var ids = threadInfo.getAllThreadIds();
        var totalCpuTime = 0;
        for (long id : ids) {
            totalCpuTime += (int) threadInfo.getThreadCpuTime(id);
        }
        log.info("Total CPU time: {}", totalCpuTime);
    }

    public int getEstimatedOptimalThreadCount() {
        var osBean = ManagementFactory.getOperatingSystemMXBean();
        if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
            // 获取CPU的核心数
            int cpuCores = osBean.getAvailableProcessors();
            // 返回基于CPU核心数的估算值
            return cpuCores * NumConstant.INT_TWO;
        }
        // 如果无法获取CPU核心数，则返回默认值
        var defaultThreads = Runtime.getRuntime().availableProcessors() * NumConstant.INT_TWO;
        log.info("无法获取CPU核心数，使用默认值:{}", defaultThreads);
        return defaultThreads;
    }
}
